package com.ruoyi.media.threadConfig;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 */
@Configuration
public class ThreadPoolTaskConfig {
    //线程执行顺序  corePoolSize -> queueCapacity -> maxPoolSize

    public static final int cpuNum = Runtime.getRuntime().availableProcessors();   //获取当前机器的线程数 io密集型

    private static final int corePoolSize = cpuNum * 4;       		// 核心线程数大小（默认线程数）
    private static final int maxPoolSize = cpuNum * 16;			    // 最大线程数
    private static final int keepAliveTime = 5;			// 允许线程空闲时间（单位：默认为秒）
    private static final int queueCapacity = 500;			// 缓冲队列数
    private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀

    @Bean("taskExecutor") // bean的名称，默认为首字母小写的方法名
    public ThreadPoolTaskExecutor getAsyncExecutor(){
        //创建线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        /**
         * 设置线程池核心容量
         * 核心线程会一直存活,即使没有任务需要处理.当线程数小于核心线程数时,
         * 即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交
         * 给现有的线程处理;核心线程在allowCoreThreadTimeout被设置为true时
         * 会超时退出,默认情况下不会退出..
         */
        executor.setCorePoolSize(corePoolSize);
        /**
         *  当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,
         *  直到线程数量达到maxPoolSize.如果线程数已等于maxPoolSize,且任务
         *  队列已满,则已超出线程池的处理能力,线程池会拒绝处理任务而抛出异常;
         */
        executor.setMaxPoolSize(maxPoolSize);
        /**
         * 任务队列容量,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置
         */
        executor.setQueueCapacity(queueCapacity);
        /**
         * 当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize
         */
        executor.setKeepAliveSeconds(keepAliveTime);
        /**
         * 线程名称 前缀
         */
        executor.setThreadNamePrefix(threadNamePrefix);
        /**
         * 当提交的任务个数大于QueueCapacity，就需要设置该参数，
         * 但spring提供的都不太满足业务场景，可以自定义一个，也可以注意不要超过QueueCapacity即可
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        /**
         * 在配置了spring线程池的情况下，如果某时刻要停止应用，如果没有优雅停机
         * 存在于线程池中的任务将会被强制停止，导致部分任务失败，true表示等待所有进程执行完后停止
         */
        executor.setWaitForTasksToCompleteOnShutdown(true);
        /**
         * 存在于线程池中的任务将会被强制停止，导致部分任务失败，等待10秒后停止
         * （默认为0，此时立即停止）
         */
        executor.setAwaitTerminationSeconds(10);

        executor.initialize();
        return executor;
    }
}

